package compoundDB.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;

import compoundDB.core.GUIController;

/**
 * CompoundDBs GUI.
 * 
 * @author Michael Ashman
 */
@SuppressWarnings("serial")
public class ResultsScreen extends JFrame implements NamesTableHolder, ColumnHolderListener
{

    private static final int screenWidth = 700;
    private static final int screenHieght = 460;
    private static final int ePanWidth = 350;
    private static final int ePanHideWidth = 10;
    private static final int[] tableColoumnWidth = {20, 30, 50};
    private static final int tableColoumnWidthdefault = 100;
    private static final int buttonWidth = 90;
    private static final int buttonWidthMenu = 80;
    private static final int buttonHight = 20;
    private static final Dimension buttonDim = new Dimension(buttonWidth, buttonHight);
    private static final Dimension buttonDimMenu = new Dimension(buttonWidthMenu, buttonHight);
    private JTable m_table;
    private ResultsScreen thisScreen = this;
    private boolean m_ePanalexpand = false;
    private Component m_eeStor;
    private TableModel m_previewModel;
    private JScrollPane m_scrollPaneNames;
    private JTable m_namesTable;
    private JPanel ePan;
    private JPanel eePan;
    private JPanel wsPan;
    private JPanel wPan;
    private JPanel nPan;
    private GUIController GUIC;
    private JFileChooser m_fileSel;
    public Boolean newSearchResults = false;

    /**
     * Constructor for a new Results Screen. This Constructor does everything,
     * just call it and the screen will apear.
     *
     * @param control
     *            The GUIController that this Results Screen will be talking to
     */
    public ResultsScreen(GUIController control)
    {
        // Setting up guicontroller
        control.setErrorDialogBox(new ErrorUserDialogImpl());
        control.setImportDialogBox(new ImportUserDialogImpl());

        // Creating the Panel
        setSize(screenWidth, screenHieght);
        setTitle("Welcome to CompoundDB");
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        GUIC = control;
        m_fileSel = new JFileChooser();
        m_fileSel.setFileHidingEnabled(true);
        // Setting it on Screen
        Dimension size = getToolkit().getScreenSize();
        setLocation(size.width / 3 * 2 - getWidth() / 2, size.height / 3 - getHeight() / 2);
        createNorthPanel();
        createEastPanel();// contains the preview table
        createWestPanel();// actually center panel // contains the results table
        setVisible(true);

    }

    /**
     * Creates the west Panel West Panel has the results table and all its
     * controls Automatically adds to frame.
     */
    private void createWestPanel()
    {
        wPan = new JPanel();
        // wPan.setBackground(Color.RED);
        wPan.setLayout(new BoxLayout(wPan, BoxLayout.Y_AXIS));

        wPan.add(createWestCenterPanel());// this must go first so the table is
        wPan.add(createWestNorthPanel());// initalized before this is called
        add(wPan, BorderLayout.CENTER);
    }

    /**
     * Creates the north panel of the 2 panels in the west panel
     *
     * @return A panel that holds the table control options like next page and
     *         etc.
     */
    private JPanel createWestNorthPanel()
    {
        JPanel wnPan = new JPanel();
        // wnPan.setBackground(Color.BLUE);
        wnPan.setPreferredSize(new Dimension(0, getSize().height / 6));
        wnPan.setMaximumSize(new Dimension(Integer.MAX_VALUE, getSize().height / 6));

        wnPan.setLayout(new BoxLayout(wnPan, BoxLayout.X_AXIS));

        JButton buttonSelectAll = new JButton("Select All");
        buttonSelectAll.setToolTipText("Selects or unselects all of the tick boxes on this page");
        buttonSelectAll.setPreferredSize(buttonDim);
        buttonSelectAll.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent event)
            {
                boolean allSelected = true;
                for (int i = 0; i < m_table.getRowCount(); i++) {
                    if (!(Boolean) m_table.getValueAt(i, 0)) {
                        allSelected = false;
                        break;
                    }
                }
                allSelected = !allSelected;// if they were all true then we want
                // them false else we want them all
                // true;
                for (int i = 0; i < m_table.getRowCount(); i++) {
                    m_table.setValueAt(allSelected, i, 0);
                }
            }
        });

        JLabel labNumOfResults = new JLabel("Entrys Per Page? ");
        final JTextField wnField = new JTextField();
        wnField.setPreferredSize(buttonDim);
        // nField.setSize(buttonDim);
        wnField.setMaximumSize(buttonDim);
        wnField.setText(((ResultsTableModel) m_table.getModel()).getEntriesPerPageIdeal() + "");
        wnField.addCaretListener(new CaretListener()
        {

            @Override
            public void caretUpdate(CaretEvent arg0)
            {
                String textWnField = wnField.getText();
                if (textWnField.equals("")) {
                    return;
                }
                try {

                    int intwnField = Integer.parseInt(textWnField);
                    if (intwnField > 0) {
                        ((ResultsTableModel) m_table.getModel()).setEntriesPerPageIdeal(intwnField);
                    } else if (intwnField < 0) {
                        throw new NumberFormatException();
                    }
                } catch (NumberFormatException e) {
                    final String temp = ((ResultsTableModel) m_table.getModel()).getEntriesPerPageIdeal() + "";

                    // uglyest bit of code ever
                    // the setText method can not be called if the user is in
                    // the middle of editing it
                    // this creates a new thread that sets the text the moment
                    // it can be set
                    EventQueue.invokeLater(new Runnable()
                    {

                        @Override
                        public void run()
                        {
                            wnField.setText(temp);
                        }
                    });
                }
            }
        });
        labNumOfResults.setLabelFor(wnField);

        JButton buttonNextPage = new JButton("Next");
        buttonNextPage.setToolTipText("Lets you see the next page of data");
        buttonNextPage.setPreferredSize(buttonDim);
        buttonNextPage.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent event)
            {
                ((ResultsTableModel) m_table.getModel()).displayNextPage();
            }
        });
        JButton buttonPrevPage = new JButton("Previous");
        buttonPrevPage.setToolTipText("Lets you see the previous page of data");
        buttonPrevPage.setPreferredSize(buttonDim);
        buttonPrevPage.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent event)
            {
                ((ResultsTableModel) m_table.getModel()).displayPrevPage();
            }
        });

        wnPan.add(Box.createHorizontalGlue());
        wnPan.add(buttonSelectAll);
        wnPan.add(Box.createHorizontalGlue());
        wnPan.add(labNumOfResults);
        wnPan.add(wnField);
        wnPan.add(Box.createHorizontalGlue());
        wnPan.add(buttonPrevPage);
        wnPan.add(Box.createHorizontalGlue());
        wnPan.add(buttonNextPage);
        wnPan.add(Box.createHorizontalGlue());

        return wnPan;
    }

    @Override
    public void updateColumns()
    {
        this.setVisible(false);
        this.remove(nPan);
        this.remove(ePan);
        this.remove(wPan);
        createNorthPanel();
        createEastPanel();// contains the preview table
        createWestPanel();// actually center panel // contains the results table
        this.setVisible(true);

    }

    /**
     * Creates the Center panel in the west panel, the bottem panel of the 2
     * panels in the west panel.
     *
     * @return A Panel that holds the table itself (table controls held in
     *         WestNorthPanel (the top panel of the 2 panels in the west panel)
     */
    private JPanel createWestCenterPanel()
    {
        wsPan = new JPanel();
        // wsPan.setBackground(Color.YELLOW);

        wsPan.setLayout(new BorderLayout());

        m_table = new JTable(new ResultsTableModel(GUIC.getColumnTitles()));
        m_table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        JScrollPane scrollPaneHorizontal = new JScrollPane(m_table);
        m_table.setAutoCreateRowSorter(true);

        m_table.setFillsViewportHeight(true);
        TableColumn column = null;
        for (int i = 0; i < m_table.getColumnCount(); i++) {
            column = m_table.getColumnModel().getColumn(i);
            // tableColoumnWidth is a final array declared at top of class
            if (i <= 2) {
                column.setPreferredWidth(tableColoumnWidth[i]);
            } else {
                column.setPreferredWidth(tableColoumnWidthdefault);
            }
        }
        m_table.getSelectionModel().addListSelectionListener(new ListSelectionListener()
        {

            @Override
            public void valueChanged(ListSelectionEvent arg0)
            {

                if (!m_ePanalexpand) {
                    return;
                }
                setPreviewToSelectedRow();
            }
        });

        wsPan.add(scrollPaneHorizontal, BorderLayout.CENTER);

        return wsPan;

    }

    /**
     * Sets the preview pane into showing the selected compound from the table
     * If no compound is selected, this method does nothing and no exception is
     * thrown
     */
    private void setPreviewToSelectedRow()
    {
        int selectedRow = m_table.getSelectedRow();
        if (selectedRow < 0) {
            return;
        }
        int dataLegnth = m_previewModel.getRowCount();
        for (int i = 0; i < dataLegnth; i++) {
            Object tempValue = m_table.getValueAt(selectedRow, i + 1);
            m_previewModel.setValueAt(tempValue, i, 1);
        }

        try {
            long guid = Long.parseLong(m_table.getValueAt(selectedRow, 1).toString());
            m_namesTable.setModel(new NamesTableModel(GUIC.getCompoundNames(guid), this, false));
            this.refreshNamesHeight();

        } catch (NumberFormatException e) {
            // Havent selected a line with a guid so do nothing
        }

    }

    /**
     * Creates and adds the East Panel The East Panel holds the hideable preview
     * pane The Preview pane starts of empty and hidden until opened.
     * Automatically adds to frame.
     */
    private void createEastPanel()
    {
        ePan = new JPanel();

        // ePan.setBackground(Color.RED);
        ePan.setPreferredSize(new Dimension(ePanHideWidth, 0));
        ePan.setLayout(new BoxLayout(ePan, BoxLayout.X_AXIS));

        JButton hider = new JButton(">");
        hider.setToolTipText("Hides This Tab");
        hider.setPreferredSize(new Dimension(ePanHideWidth, getSize().height * 9 / 10));
        hider.setMaximumSize(new Dimension(ePanHideWidth, Integer.MAX_VALUE));
        hider.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent event)
            {
                m_ePanalexpand = !m_ePanalexpand;
                if (!m_ePanalexpand) {
                    ePan.setPreferredSize(new Dimension(ePanHideWidth, 0));
                    m_eeStor = ePan.getComponent(1);
                    ePan.remove(m_eeStor);
                } else {
                    ePan.setPreferredSize(new Dimension(ePanWidth, 0));
                    if (m_eeStor == null) {
                        ePan.add(createEastEastPanel());
                    } else {
                        ePan.add(m_eeStor);
                    }
                }
                ePan.updateUI();
                setPreviewToSelectedRow();
            }
        });
        ePan.add(hider);
        if (m_ePanalexpand) {
            ePan.setPreferredSize(new Dimension(ePanWidth, 0));
            ePan.add(createEastEastPanel());
        }
        add(ePan, BorderLayout.EAST);
    }

    @Override
    public void refreshNamesHeight()
    {

        if (m_namesTable.getModel().getRowCount() < 8) {
            int temp = m_namesTable.getModel().getRowCount();
            m_scrollPaneNames.setPreferredSize(new Dimension(0, (temp) * m_namesTable.getRowHeight() * 2));
        } else {
            m_scrollPaneNames.setPreferredSize(new Dimension(0, (10) * m_namesTable.getRowHeight()));
        }
        ePan.updateUI();
    }

    /**
     * Creates the East East Panel. This Panel is on the far right and holds the
     * preview panel.
     *
     * @return A panel containts a table that has all of the properties down the
     *         side. To update this table to the row that has been selected call
     *         setPreviewToSelectedRow().
     */
    private JPanel createEastEastPanel()
    {
        eePan = new JPanel();
        eePan.setLayout(new BoxLayout(eePan, BoxLayout.Y_AXIS));

        // Preview Picture
        // TODO: Yet To Implement Compound Pictures (Low Piority)
        // Preview Properties
        Object[][] preview = new Object[m_table.getColumnCount() - 1][2];
        for (int i = 1; i < m_table.getColumnCount(); i++) {
            preview[i - 1][0] = m_table.getColumnName(i);
            preview[i - 1][1] = "None";
        }

        JTable previewTable = new JTable(new PreviewTableModel(new String[]{"Property", "Value"}, preview, false));
        m_previewModel = previewTable.getModel();
        previewTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        JScrollPane preScroll = new JScrollPane(previewTable);
        previewTable.getColumnModel().getColumn(0).setPreferredWidth((ePanWidth - ePanHideWidth * 2 - 2) / 2);
        previewTable.getColumnModel().getColumn(1).setPreferredWidth((ePanWidth - ePanHideWidth * 2 - 2) / 2);

        // Names for Compound
        m_namesTable = new JTable(new NamesTableModel(new String[0], this, false));
        m_scrollPaneNames = new JScrollPane(m_namesTable);
        m_scrollPaneNames.setPreferredSize(new Dimension(0, (3) * m_namesTable.getRowHeight()));

        eePan.add(preScroll);
        eePan.add(m_scrollPaneNames);
        return eePan;

    }

    /**
     * This panel is the North panel. It contains buttons like add and edit.
     * Automatically adds to frame.
     */
    private void createNorthPanel()
    {
        nPan = new JPanel();
        nPan.setBackground(Color.BLACK);
        nPan.setPreferredSize(new Dimension(0, buttonHight + 15));
        nPan.setLayout(new BoxLayout(nPan, BoxLayout.X_AXIS));

        JButton butAdd = new JButton("Add...");
        butAdd.setToolTipText("Adds a compound to the database");
        butAdd.setPreferredSize(buttonDimMenu);

        butAdd.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent event)
            {
                if (event.getSource().getClass() == JButton.class) {
                    DialogAdd add = new DialogAdd("Add Compound", GUIC.getColumnTitles());
                    add.addActionListener(this);
                    add.go();
                } else if (event.getSource().getClass() == DialogAdd.class) {
                    DialogAdd add = (DialogAdd) event.getSource();
                    GUIC.addCompound(add.getArrayProperties(), add.getArrayNames());
                    add.dispose();
                }
            }
        });
        JButton butEdit = new JButton("Edit...");
        butEdit.setToolTipText("Edit the selected compound");
        butEdit.setPreferredSize(buttonDimMenu);
        butEdit.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent event)
            {
                if (event.getSource().getClass() == JButton.class) {
                    int selectedRow = m_table.getSelectedRow();
                    if (selectedRow < 0) {
                        JOptionPane.showMessageDialog(null, "Please select a row in the table, then try agains");
                        return;
                    }
                    int dataLegnth = GUIC.getColumnTitles().length;
                    Object[] compound = new Object[dataLegnth];
                    for (int i = 0; i < dataLegnth; i++) {
                        compound[i] = m_table.getValueAt(selectedRow, i);
                    }
                    Long guid;
                    try {
                        guid = (long) Long.parseLong(compound[1].toString());
                    } catch (NumberFormatException e) {
                        JOptionPane.showMessageDialog(null, "Please select a row in the table that is not empty, then try agains");
                        return;
                    }
                    String[] temp = GUIC.getCompoundNames(guid);
                    DialogAdd add = new DialogAdd("Edit Compound", GUIC.getColumnTitles(), compound, temp);
                    add.addActionListener(this);
                    add.go();
                } else if (event.getSource().getClass() == DialogAdd.class) {
                    DialogAdd edit = (DialogAdd) event.getSource();
                    Object[] eComp = edit.getArrayProperties();
                    GUIC.editCompound(eComp, edit.getArrayNames());
                    ((ResultsTableModel) m_table.getModel()).setRow(m_table.getSelectedRow(), eComp);
                    edit.dispose();
                }
            }
        });
        JButton butDel = new JButton("Delete");
        butDel.setToolTipText("Deletes a compound from the database");
        butDel.setPreferredSize(buttonDimMenu);
        butDel.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent event)
            {
                try {
                    List<Integer> indexes = ((ResultsTableModel) m_table.getModel()).getSelectedCompounds();
                    String question;
                    if (indexes.size() == 0) {
                        JOptionPane.showMessageDialog(null, "Please select a row (or rows) in the table that is not empty, then try agains");
                        return;
                    }
                    if (indexes.size() == 1) {
                        question = "Are you sure you want to delete " + m_table.getValueAt(indexes.get(0), 3).toString() + "?";
                    } else {
                        question = "Are you sure you want to delete these " + indexes.size() + " compounds?";
                    }

                    int result = JOptionPane.showConfirmDialog(null, question, "Input", JOptionPane.YES_NO_OPTION);
                    if (result == 0) {
                        List<Long> guids = new ArrayList<Long>();
                        for (int i = 0; i < indexes.size(); i++) {
                            guids.add(Long.parseLong(m_table.getValueAt(indexes.get(i), 1).toString()));
                        }
                        GUIC.deleteCompound(guids);
                        ((ResultsTableModel) m_table.getModel()).deleteCompound(guids);
                    }
                } catch (Exception e) {
                    JOptionPane.showMessageDialog(null, "Please select a row (or rows) in the table that is not empty, then try agains");
                }
            }
        });
        JButton butImp = new JButton("Import");
        butImp.setToolTipText("Import compounds from a external source");
        butImp.setPreferredSize(buttonDimMenu);
        butImp.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent event)
            {
                m_fileSel.setCurrentDirectory(new File("plugins"));
                int returnVal = m_fileSel.showOpenDialog(thisScreen);

                if (returnVal == JFileChooser.APPROVE_OPTION) {
                    File file = m_fileSel.getSelectedFile();
                    GUIC.importCompounds(file.getAbsolutePath());
                }
            }
        });

        JButton butExp = new JButton("Export");
        butExp.setToolTipText("Export compounds to a external destination");
        butExp.setPreferredSize(buttonDimMenu);
        butExp.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent event)
            {
                m_fileSel.setCurrentDirectory(new File("exports"));
                int returnVal = m_fileSel.showSaveDialog(thisScreen);

                if (returnVal == JFileChooser.APPROVE_OPTION) {
                    File file = m_fileSel.getSelectedFile();

                    List<Integer> indexes = ((ResultsTableModel) m_table.getModel()).getSelectedCompounds();

                    if (indexes.size() > 0) {
                        List<Long> guids = new ArrayList<Long>();
                        for (int i = 0; i < indexes.size(); i++) {
                            guids.add(Long.parseLong(m_table.getValueAt(indexes.get(i), 1).toString()));
                        }

                        GUIC.exportCompounds(guids, file.getAbsolutePath());
                    }
                }
            }
        });
        JButton butEditColumns = new JButton("Column");
        butEditColumns.setToolTipText("Changes the columns of the database");
        butEditColumns.setPreferredSize(buttonDimMenu);
        butEditColumns.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent event)
            {
                String[] cols = GUIC.getColumnTitles();
                String[] colsEditable = new String[cols.length - 3];
                for (int i = 3; i < cols.length; i++) {
                    colsEditable[i - 3] = cols[i];
                }
                new DialogCol(colsEditable, GUIC, thisScreen);
            }
        });

        final JTextField nField = new JTextField();
        nField.setMaximumSize(new Dimension(Integer.MAX_VALUE, buttonHight));
        class nFieldActionListner implements ActionListener
        {

            @Override
            public void actionPerformed(ActionEvent arg0)
            {
                String str = nField.getText();
                if (str.equals("")) {
                    String[] columns = GUIC.getColumnTitles();
                    String[] columnsNoSel = new String[columns.length - 1];
                    for (int i = 1; i < columns.length; i++) {
                        columnsNoSel[i - 1] = columns[i];
                    }

                    new DialogAdv(columnsNoSel, thisScreen, GUIC);
                    if (newSearchResults) {
                        Object[][] tempData = GUIC.getSearchResults(1, GUIC.getSearchResultCount());
                        ((ResultsTableModel) m_table.getModel()).SetData(tempData);
                        thisScreen.setTitle("Results For Advanced Search");
                    }

                } else {
                    nField.setText("");
                    thisScreen.setTitle("Searching For " + str);
                    GUIC.quickSearch(str);
                    Object[][] tempData = GUIC.getSearchResults(1, GUIC.getSearchResultCount());
                    ((ResultsTableModel) m_table.getModel()).SetData(tempData);
                    thisScreen.setTitle("Results For " + str);
                }
            }
        }
        nField.addActionListener(new nFieldActionListner());

        JButton butSearch = new JButton("?");
        butSearch.setToolTipText("Search the database");
        butSearch.setPreferredSize(new Dimension(buttonHight, buttonHight));
        butSearch.addActionListener(new nFieldActionListner());

        nPan.add(Box.createHorizontalStrut(5));
        nPan.add(butAdd);
        nPan.add(Box.createHorizontalStrut(5));
        nPan.add(butEdit);
        nPan.add(Box.createHorizontalStrut(5));
        nPan.add(butDel);
        nPan.add(Box.createHorizontalStrut(5));
        nPan.add(butImp);
        nPan.add(Box.createHorizontalStrut(5));
        nPan.add(butExp);
        nPan.add(Box.createHorizontalStrut(5));
        nPan.add(butEditColumns);
        nPan.add(Box.createHorizontalStrut(5));
        nPan.add(nField);
        nPan.add(butSearch);
        nPan.add(Box.createHorizontalStrut(5));

        add(nPan, BorderLayout.NORTH);
    }
}
